#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#include<cstdlib>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>


//把5个子进程要管理起来，要先描述再组织
const int processnum=5;
//先描述
class channel
{
public:
    channel(pid_t slaverpid,int cmdfd,std::string slavername)
    :_slaverpid(slaverpid),_slavername(slavername),_cmdfd(cmdfd)
    {}
public:
    pid_t _slaverpid;//子进程pid
    int _cmdfd;//发送任务的文件描述符
    std::string _slavername;//子进程的名字，方便打印日志
};


void  Slaver()
{
    while(true)
    {
        int cmdnode=0;
        int n=read(0,&cmdnode,sizeof(int));
        if(n==sizeof(int))
        {
            std::cout<<std::endl;
            std::cout <<"slaver say@ get a command: "<< " cmdcode: " << cmdnode << std::endl;
            //执行任务列表
            switch(cmdnode)
            {
                case 1:
                {
                    std::cout<<"刷新野怪"<<std::endl;
                    break;
                }
                case 2:
                {
                    std::cout<<"购买装备"<<std::endl;
                    break;
                }
                case 3:
                {
                    std::cout<<"释放技能"<<std::endl;
                    break;
                }               
                case 4:
                {
                    std::cout<<"查看战绩"<<std::endl;
                    break;
                }
            }

        }
        if(n==0) break;
    }
}
void Initprocesspool(std::vector<channel>& channels)
{
    std::vector<int> oldwfd;//用来存储旧的写端fd， 确保每一个子进程都只有一个写端
    for(int i=0;i<processnum;i++)
    {
        int pipefd[2]={0};
        int n=pipe(pipefd);
        if(n<0) return ;


        pid_t id=fork();
        if(id==0) //child
        {
            for(auto& fd:oldwfd) close(fd);//关闭从父进程继承下来的写端
            close(pipefd[1]);

            dup2(pipefd[0],0);//把标准输入重定向到读端文件，简化代码，可以不这么写
            Slaver();
            close(pipefd[0]);
            exit(0);
        }

        close(pipefd[0]);

        //添加channel字段
        std:: string name="process-"+std::to_string(i);
        channels.push_back(channel(id,pipefd[1],name));
        oldwfd.push_back(pipefd[1]);
        
        
    }

}
void Debug(const std::vector<channel> &channels)
{
    // test
    for(const auto &c :channels)
    {
        std::cout << c._cmdfd << " " << c._slaverpid << " " << c._slavername << std::endl;
    }
}

void menu()
{
    std::cout<<"###########################################"<<std::endl;
    std::cout<<"######     1.刷新野怪       2.购买装备######"<<std::endl;
    std::cout<<"######     3.释放技能       4.查看战绩#######"<<std::endl;
    std::cout<<"######               0.退出          #######"<<std::endl;
    std::cout<<"###########################################"<<std::endl;
}
void Ctrlprocess(std::vector<channel> channels)
{
    
    while(true)
    {
        int select=0;
        menu();
        std::cout<<"please select@";
        std::cin>>select;
        if(select<1||select>4) break ;

        //选择进程,随机选择
        int processpos=rand()%channels.size();

        std::cout<<"father say:"<<"select:"<<select<<"  can todo "<<
        channels[processpos]._slaverpid<<"slavername:"<<channels[processpos]._slavername<<std::endl;

        //发放任务
        write(channels[processpos]._cmdfd,&select,sizeof(select));
        sleep(1);

    }
}

void Quitprocess(const std::vector<channel>& channels)
{
    for(const auto& process:channels)
    {
        close(process._cmdfd);
        waitpid(process._slaverpid,nullptr,0);
    }
}

int main()
{
    srand(time(nullptr));
    std::vector<channel> channels;
    //1.初始化进程池
    Initprocesspool(channels);
    Debug(channels);

    //2.控制子进程
    Ctrlprocess(channels);

    //3.清理收尾

    Quitprocess(channels);

    return 0;


}


